home *** CD-ROM | disk | FTP | other *** search
- /*
- SNEWS 2.0
-
- History routines
-
-
- Copyright (C) 1991 John McCombs, Christchurch, NEW ZEALAND
- john@ahuriri.gen.nz
- PO Box 2708, Christchurch, NEW ZEALAND
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License, version 1, as
- published by the Free Software Foundation.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- See the file COPYING, which contains a copy of the GNU General
- Public License.
-
-
- */
-
- /*---------------------------- Source Control ------------------------------*/
-
- /*
- * $Id: HISTORY.C,v 1.2 1994/02/05 18:48:42 gbj Exp user $
- */
-
- /****************************************************************************
- * 06 Jun 92 1.2 GT Invalidate freed pointers. *
- * Fix NULL pointer dereference. *
- * 12 Jun 92 1.3 NJL Restructure add_hist_record() routine. *
- * Fix find_msg_id() to resolve hash collisions. *
- * Put ALL messages in history file to catch any *
- * duplicates whilst processing CIX scratchpads. *
- * Actually this belongs in the CIX unbatcher. *
- * Ensure strtok() accepts tab as well as space. *
- * 02 Jul 92 1.4 GT Change history file name. *
- * 17 Jul 92 1.5 GT C++ compilation. *
- * Heap debugging. *
- * 16 Aug 92 1.6 MSM Snews 1.9 *
- * Flush writes to history.snw *
- * 31 May 93 2.7 MSM Snews 2.0 *
- * 18 Jun 93 2.8 MSM Heap debugging removed (using Bounds Check) *
- * 18 Sep 93 2.9 MSM File handle loss problem fixed *
- ****************************************************************************/
-
- #include "defs.h"
- #include "history.h"
- #include <io.h>
- #include <ctype.h>
-
- #ifdef ATARI
- # include "fileops.h"
- # include "screen.h"
- #endif
-
- #ifndef __TURBOC__
- #ifndef ATARI
- unsigned long farcoreleft(void);
- unsigned long testcoreleft(void);
- #endif
- #endif
-
- static FILE *hist = NULL;
- static HIST_LIST *hlist, *hlistend;
-
-
- /*----------------------- open hist file for writing ------------------------*/
- FILE *open_hist_file(void)
- {
-
- /*
- * This routine opens the history file for writing, positioned after
- * the last record.
- */
-
- char fn[256];
-
- sprintf(fn, "%shistory.snw", my_stuff.news_dir);
-
- if (hist != NULL) {
- fclose(hist);
- hist = NULL;
- }
-
- if ((hist = fopen(fn, "a+b")) == NULL) {
- fprintf(stderr, "history: cannot open file %s for append\n", fn);
- exit(1);
- }
-
- return (hist);
- }
-
-
- /*---------------------------- close hist file ---------------------------*/
- void close_hist_file(void)
- {
-
- /*
- * This routine closes the history file
- */
-
- if (hist != NULL) {
- fclose(hist);
- hist = NULL;
- }
- }
-
-
- /*---------------------------- add record to list ------------------------*/
- int add_to_hist_list(char *p, int ct, long where)
- {
-
- /*
- * This routine adds a single entry to the history list in memory. It returns 1 if store is exhausted, else zero.
- */
-
- if (hlist == NULL) {
- hlist = (HIST_LIST *) malloc(sizeof(HIST_LIST));
- hlistend = hlist;
- }
- else {
- hlistend->next = (HIST_LIST *) malloc(sizeof(HIST_LIST));
- hlistend = hlistend->next;
- }
-
- hlistend->mid = hash_msg_id(p);
- hlistend->ngroups = ct;
- hlistend->offset = where;
- hlistend->next = NULL;
-
- /* leave some memory for other things */
- #ifdef ATARI
- if (farcoreleft() < HIST_MEM_LIMIT)
- #else
- #ifdef __TURBOC__
- if (farcoreleft() < HIST_MEM_LIMIT)
- #else
- if (testcoreleft() < HIST_MEM_LIMIT)
- #endif
- #endif
-
- return (1);
- else
- return (0);
- }
-
- /*---------------------------- add record to file -----------------------*/
- void add_hist_record(char *msg_id, char *ng)
- {
-
- /*
- * This routine adds a record to the history files. It is passed the
- * message id, and the newsgroup list. The newsgroup list is unwound,
- * and the article numbers are added to the record.
- *
- * We assume that this routine is called after the article has been
- * posted, so that the article counters are correct.
- */
-
-
- char *p;
- static char buf[512];
- ACTIVE *a;
- time_t t;
- int ct;
- int junk_flag; /* nz - target is junk group */
- #ifndef ATARI
- int dup_h;
- #endif
-
- time(&t);
-
- /* count the newsgroups */
-
- strcpy(buf, ng);
- p = strtok(buf, " \t,\n\r");
- ct = 0;
-
- while (p != NULL) {
- ct++;
- p = strtok(NULL, " \t,\n\r");
- }
-
- strcpy(buf, ng);
- p = strtok(buf, " \t,\n\r");
-
- if ((p != NULL) && (strlen(msg_id) > 0)) {
-
- fseek(hist, 0L, SEEK_END);
-
- add_to_hist_list(msg_id, ct, ftell(hist));
-
- fprintf(hist, "%s %09ld ", msg_id, t);
-
- while (p != NULL) {
- a = find_news_group(p, &junk_flag);
- fprintf(hist, "%s %08ld ", a->group, a->hi_num);
- p = strtok(NULL, " \t,\n\r");
- }
- fprintf(hist, "\n");
- #ifdef ATARI
- fflush(hist);
- #else
- dup_h = dup(fileno(hist));
- close(dup_h);
- #endif
- if (ferror(hist))
- perror("Error whilst appending to History file");
- }
- }
-
-
- /*--------------------- read history file into ram -------------------------*/
- HIST_LIST *load_history_list(int all)
- {
-
- /*
- * This routine opens and reads the history file, building and index
- *
- * Load this after active and ng files. Set HIST_MEM_LIMIT in defs.h
- * to ensure there is enough memory left
- */
-
- static char buf[512];
- char *msg_id, *p;
- int ct, ans = 0;
- long where;
-
- sprintf(buf, "%shistory.snw", my_stuff.news_dir);
-
- if (hist != NULL)
- {
- fclose(hist);
- hist = NULL;
- }
-
- if ((hist = fopen(buf, "rb")) == NULL) {
- fprintf(stderr, "history: cannot find history file <%s>\n", buf);
- fprintf(stderr, " make new one ? (Y/N) ");
- ans = getch();
- ans = tolower(ans);
- putch(ans);
- if (ans == (int) 'y') {
- if ((hist = fopen(buf, "w+b")) == NULL) {
- fprintf(stderr, "history: cannot make history file <%s>\n", buf);
- exit(1);
- }
- }
- else
- exit(1);
- }
-
- where = 0;
- hlist = hlistend = NULL;
-
- while (fgets(buf, 511, hist)) {
-
- msg_id = strtok(buf, " \t\n\r");
-
- /* skip the next entry */
- p = strtok(NULL, " \t\n\r");
-
- /* now count the newsgroups */
- ct = 0;
-
- p = strtok(NULL, " \t\n\r");
- while (p != NULL) {
- ct++;
- p = strtok(NULL, " \t,\n\r");
- p = strtok(NULL, " \t,\n\r");
- }
-
- if ((all == 0) || (ct > 1))
- ans = add_to_hist_list(msg_id, ct, where);
-
- if (ans)
- break;
-
- where = ftell(hist);
- }
-
- return (hlist);
- }
-
- /*------------------------- release the history list ----------------------*/
- void free_hist_list(void)
- {
-
- /*
- * Close the history file and free the memory list
- */
-
- HIST_LIST *h;
-
- close_hist_file();
-
- while (hlist != NULL) {
- h = hlist->next;
- free(hlist);
- hlist = h;
- }
- }
-
- /*-------------------------- find history entry -----------------------------*/
- HIST_LIST *find_msg_id(char *msg_id)
- {
-
- /*
- * Look up the history list and return the entry for the req'd msg id
- * or NULL if not found. ASSUMES global file 'hist' is open. If it
- * isn't this routine always returns NULL.
- */
-
- static char buf[512]; /* THIS MUST BE STATIC !!! */
- HIST_LIST *h;
- char *p;
- long hashed_id;
-
- hashed_id = hash_msg_id(msg_id);
-
- for (h = hlist; h != NULL; h = h->next) {
- if (h->mid == hashed_id) {
- /* Look up this entry in the file */
- fseek(hist, h->offset, SEEK_SET);
- if (fgets(buf, 511, hist)) {
-
- /*
- * Compare the target msg id with the one on the file.
- * If they are different then there must be a
- * hash collision so we must continue searching.
- */
-
- p = strtok(buf, " \t\n\r");
- if (stricmp(p, msg_id) == 0)
- return (h);
- }
- }
- }
-
- return (NULL);
- }
-
- /*----------------------- lookup cross posts --------------------------------*/
- CROSS_POSTS *look_up_history(char *msg_id, char *ng)
- {
-
- /*
- * This routine returns a linked list of the groups to which
- * an article has been crossposted. Self is excluded. To do
- * this we:
- * - hash the msg id
- * - search the list of id's
- * - if a hit is found we read it from the hist file
- * - decode the record, excluding self
- * - build a CROSS_POSTS list
- *
- * NULL is returned if there were no crossposts.
- */
-
- HIST_LIST *h;
- CROSS_POSTS *cx, *c;
- char *p;
-
- h = find_msg_id(msg_id);
- #ifdef ATARI
- if (h == NULL)
- return NULL;
- if (h->ngroups < 2)
- return NULL;
- #else
- if (h == NULL || h->ngroups < 2)
- return (NULL); /* GT 06 Jun 92 */
- #endif
- cx = NULL;
- c = NULL;
-
- /*
- * skip the date field and leave pointing to the first group.
- * Wot a bodge. Strtok is now returning fields from the
- * buffer in find_msg_id. Good job it's static ;-)
- */
-
- p = strtok(NULL, " \t\n\r"); /* get date */
- p = strtok(NULL, " \t\n\r"); /* get first newsgroup */
-
- while (p != NULL) {
-
- /* exclude self */
- if (stricmp(p, ng) != 0) {
- if (cx == NULL) {
- cx = (CROSS_POSTS *) malloc(sizeof(CROSS_POSTS));
- c = cx;
- }
- else {
- c->next = (CROSS_POSTS *) malloc(sizeof(CROSS_POSTS));
- c = c->next;
- }
-
- strcpy(c->group, p);
- p = strtok(NULL, " \t\n\r"); /* get local article number */
- c->art_num = atol(p);
- } /* if (stricmp(p, ng) != 0) */
- else {
- /* eat article number */
- p = strtok(NULL, " \t\n\r");
- }
-
- if (c != NULL) /* GT 06 Jun 92 */
- c->next = NULL;
-
- p = strtok(NULL, " \t\n\r"); /* get next newsgroup */
- } /* while (p != NULL) */
-
- return (cx);
-
- }
-
- /*----------------------- deallocate crosspost list --------------------------*/
- void free_cross_post_list(CROSS_POSTS * cx)
- {
- CROSS_POSTS *c;
-
- while (cx != NULL) {
- c = cx->next;
- free(cx);
- cx = c;
- }
-
- }
-
- /*------------------------ random number generator -------------------------*/
- long seed;
-
- long xrand(void)
- {
- seed = (seed * 16807) & 0x7FFFFFFFL;
- return (seed);
- }
-
- /*----------------------------- hash a key -----------------------------------*/
- long hash_key(long s, char *key)
- {
- long hash_num;
- int i;
-
- hash_num = 0;
- seed = s;
-
- for (i = 0; i < (int)strlen(key); i++) {
- hash_num += xrand() * (key[i] + 0xFF00);
- }
-
- hash_num = hash_num & 0x7FFFFFFFL;
- if (hash_num == 0)
- hash_num++;
-
- return (hash_num);
- }
-
-
- /*----------------------------- hash the message id -------------------------*/
- long hash_msg_id(char *msg_id)
- {
-
- return (hash_key(hash_key(26l, msg_id), msg_id));
- }
-